package com.javasea.qrprint.util;

import com.javasea.qrprint.entity.Result;
import com.javasea.qrprint.lib.TscLibDll;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.*;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 *@ClassName CommandUtil
 *@Description TODO
 *@Author longxiaonan@163.com
 *@Date 2022/3/25 0025 15:57
 */
@Slf4j
public class TscCommandUtil {

    /**
     * 转图片为位图并生成打印指令
     */
    public static byte[] makeBitmapAndCmd(Image snapshotImage, ImageView bitMapImageView) throws IOException {
        PixelReader pixelReader = snapshotImage.getPixelReader();
        int width = (int) snapshotImage.getWidth();
        int height = (int) snapshotImage.getHeight();

        WritableImage bitmapImage = new WritableImage(width, height);
        PixelWriter bitmapImageWriter = bitmapImage.getPixelWriter();

        int widthInCmd = width;
        List<Byte> allByte = new ArrayList<>();
        for (int j = 0; j < height; j++) {
            List<Integer> widthList = new ArrayList<>();
            for (int i = 0; i < width; i++) {
                int argb = pixelReader.getArgb(i, j);
                int rgb = argb & 0x00FF_FFFF;
                int threshold = 244;
                boolean darker = (((argb & 0x00FF_0000) >>> 4 < threshold) || ((argb & 0x0000_FF00) >>> 2 < threshold) || (argb & 0x0000_00FF) < threshold);
                if (rgb != 0x00FF_FFFF && darker) {
                    widthList.add(0);
                    bitmapImageWriter.setArgb(i, j, 0xFF00_0000);
                } else {
                    widthList.add(1);
                    bitmapImageWriter.setArgb(i, j, 0xFFFF_FFFF);
                }
//				widthList.add(1); // 1 is white, 0 is black
//				bitmapImageWriter.setArgb(i, j, 0xFF00_FFFF);
                // 0xFF00_0000 black
                // 0xFFFF_0000 red
                // 0xFF00_FF00 green
                // 0xFF00_00FF blue
                // 0xFFFF_FFFF white
            }
            List<Byte> rowByte = shrinkByteToBit(widthList);
            widthInCmd = rowByte.size();
            allByte.addAll(rowByte);
        }

        byte[] bs = new byte[allByte.size()];
        for (int i = 0; i < bs.length; i++) {
            bs[i] = allByte.get(i);
        }

        bitMapImageView.setImage(bitmapImage);

        BufferedImage bufferedImage = SwingFXUtils.fromFXImage(bitmapImage, null);
        String tmpDir = "tmp";
        String fileName = tmpDir + "/当前打印的二维码图片.png";
        File file = new File(tmpDir);
        if(!file.exists()){
            file.mkdirs();
        }
        fileName = tmpDir + "/打印样例.png";
        ImageIO.write(bufferedImage, "PNG", new File(fileName));

        String bitmap = "BITMAP 60,20,{x},{y},0,".replace("{x}", widthInCmd+"").replace("{y}", height+"");
        byte[] cmd = assembleCmd(bitmap, bs);
        return cmd;
    }

    private static byte[] assembleCmd(String cmdHead, byte[] bitmapBody) {
        byte[] cmdHeadBytes = cmdHead.getBytes();
        byte[] joined = new byte[cmdHeadBytes.length + bitmapBody.length];
        System.arraycopy(cmdHeadBytes, 0, joined, 0, cmdHeadBytes.length);
        System.arraycopy(bitmapBody, 0, joined, cmdHeadBytes.length, bitmapBody.length);

        return joined;
    }
    private static List<Byte> shrinkByteToBit(List<Integer> widthList) {
        List<AtomicReference<Byte>> rowByte = new ArrayList<>();
        AtomicReference<Byte> ref = null;
        for (int i = 0; i < widthList.size(); i++) {
            if (i % 8 == 0) {
                ref = new AtomicReference<Byte>();
                Byte b = new Byte("0");
                ref.set(b);
                rowByte.add(ref);
            }
            Byte b = ref.get();
            b = (byte) (b << 1 & 0xFF);
            Integer integer = widthList.get(i);
//            Assert.assertTrue(integer < 2);
            b = (byte) ((b + integer) & 0xFF);
            ref.set(b);
        }
        List<Byte> collect = rowByte.stream().map(r -> r.get()).collect(Collectors.toList());
        return collect;
    }

    public static Result executePrintCmd(byte[] cmd, String printModel) {
        Result result = null;
        try {
            System.setProperty("jna.encoding", "GBK");
            int openport = TscLibDll.INSTANCE.openport(printModel);
            int sendcommand = TscLibDll.INSTANCE.sendcommand("CODEPAGE 1252");
//            int sendcommand1 = TscLibDll.INSTANCE.sendcommand("DENSITY 12");
            int sendcommand2 = TscLibDll.INSTANCE.sendcommand("DIRECTION 1");
            int clearbuffer = TscLibDll.INSTANCE.clearbuffer();

            /** bitmap单次的数据467的长度在65380,469长度在65660左右，sendBinaryData的长度单次的没有做分包处理，可能会受到65535长度的影响，尝试将数据分成两段，
             * 前面那段用sendBinaryDataNoCRLF发送，结尾部分的用sendBinaryData发送，
             sendBinaryDataNoCRLF与sendBinaryData的参数一致，不过不会自动帮你加换行 */
            if(cmd.length > 65535){
                int split = 65535;
                byte[] cmdPart1 = Arrays.copyOf(cmd, split);
                byte[] cmdPart2 = new byte[cmd.length - split];
                System.arraycopy(cmd, split, cmdPart2, 0, cmdPart2.length);
                int send1 = TscLibDll.INSTANCE.sendBinaryDataNoCRLF(cmdPart1, cmdPart1.length);
                int send2 = TscLibDll.INSTANCE.sendBinaryData(cmdPart2, cmdPart2.length);
            }else{
                int send = TscLibDll.INSTANCE.sendBinaryData(cmd, cmd.length);
            }

            /** !!!!!!!!!!!!!!!!真正执行打印，打印测试 跳过打印 注释 */
            int printlabel = TscLibDll.INSTANCE.printlabel("1", "1");
            /** 打印测试 时放开注释 start */
//            int printlabel = 1;
            /** 打印测试 时放开注释 end */
            log.error("获取到打印状态为:[{}]", printlabel);
            int closeport = TscLibDll.INSTANCE.closeport();
            log.error("关闭端口closeport:[{}]", closeport);
            if (printlabel == 1) {
                result = Result.builder().code(1).message("已发送打印！").build();
            } else {
                result = Result.builder().code(0).message("打印失败！").build();
            }
        } catch (Exception e) {
            result = Result.builder().code(0).message("发送到打印机后发生异常！").build();
            log.error("发送到打印机后发生异常！",e);
        }
        return result;
    }

}
